//============================================================================
// Name        : ROMS_main.cpp
// Author      : 
// Version     :
// Copyright   : Your copyright notice
// Description : C++ project Part II for your class (121, or 112) 
//============================================================================
//
#include "Simple_window.h"
#include "Graph.h"
#include <FL/Fl_Menu_Bar.H>
#include <FL/Fl_File_Chooser.H>
#include <FL/Fl_Text_Display.H>

#include "ROMS_Menu.h"

using namespace std;
using namespace ROMS;
using namespace Graph_lib;

//types we need for a ROMS GUI interface-- a memu_bar and a place to display text and a means of attaching them to a Window.

namespace Graph_lib {
//------------------------------------------------------------------------------
	struct Window_text_display : Widget {
		Window_text_display(Point XY, int W, int H, string L, Callback cb): Widget(XY, W, H, L, cb)
		{}
		void set_buffer(string s);
		void attach(Window&);
	private:
		Fl_Text_Buffer data;
		Fl_Text_Display *ptd;

	};
	void Window_text_display::attach(Window& win)
	{
		ptd = new Fl_Text_Display(loc.x, loc.y, width, height, label.c_str());
		ptd->buffer(&data);
		pw  = (Fl_Widget*) ptd;
		pw->callback(reinterpret_cast<Fl_Callback*>(do_it), &win); // pass the window
		own = &win;
	}
	void Window_text_display::set_buffer(string s) 
	{
		data.text(s.c_str());
	}

//------------------------------------------------------------------------------
	struct Menu_bar : Widget {
		Menu_bar(Point XY, int W, int H, Callback cb): Widget(XY, W, H, "", cb)
		{}
		void menu(Fl_Menu_Item *ma);
		void attach(Window&);
	private:
		Fl_Menu_Bar *pmb;
		Fl_Menu_Item *ma;

	};
	void Menu_bar::attach(Window& win)
	{
		pmb = new Fl_Menu_Bar(loc.x, loc.y, width, height);
		pmb->menu(ma);
		pw  = (Fl_Widget*) pmb;
		pw->callback(reinterpret_cast<Fl_Callback*>(do_it), &win); // pass the window
		own = &win;
	}
	void Menu_bar::menu(Fl_Menu_Item *m) 
	{
		ma = m;
	}
}

//header declarations
void do_about_box(Window&);
void do_help_box(Window&); // added by NI B.3
void find_total_sales_given_table_box(Window&, ROMS_Menu&); // added by NI -- find total sales window
void update_new_order_item_box(Window&, ROMS_Menu&); // added by NI -- add order item window
string do_find_table_button(int, ROMS_Menu&); //added by NI -- total sales output
void draw_graph(Window&, ROMS_Menu&); //added by NI -- part D, Graph
void draw_server_graph(Window&, ROMS_Menu&); //EC Part D3
void find_menu_item_sales_given_item_box(Window&, ROMS_Menu&); //EC for Part C: find total sales for menu item
void update_new_category_box(Window&, ROMS_Menu&); //EC for Part C: add category
string do_find_item_button(int, ROMS_Menu&); //EC for Part C: item sales output
/****CZ Step C****/
void update_menu_item_box(Window&, ROMS_Menu&);
void find_server_sales_box(Window&, ROMS_Menu&);
string do_find_server_sales_button(int, ROMS_Menu&);
/****CZ Step C****/
void draw_table_graph(Window&, ROMS_Menu&);	//CZ Part D.2
void do_read(Window&, ROMS_Menu&, string, string, Msg_type);
void Main_Window_CB(Fl_Widget*, void*);
void Menu_Bar_CB (Fl_Widget*, void*);

//global data
bool main_window_click = false;
bool menu_bar_click = false;
bool main_click_enabled = true;//used to force serialization on clicks
bool orders_read = false;	//CZ
bool recipes_read = false;	//CZ
bool catmenu_read = false;	//CZ
int window_userdata;

//main window menu bar
//Note: for expediancy sake, to define the menu bar below we used an FLTK type Fl_Menu_Item. 
//This makes our program  directly tied to FLTK instead of Dr. Stroustrup's interface Graph_lib.
//We don't like this, but we did it to save time, which often happens in the real world.
//A better solution is to write code to hide this in the implementation of the Graph_lib::Menu_bar, but that means adding
//changes to it and getting general agreement with Dr. Stroustrup. Subsequent testing and distribution would take time we don't have.
//An extra credit exercise is to see if you can eliminate direct references in your code to FLTK types like we have here
Fl_Menu_Item menu_bar[] = {
 {"Read", 0,  0, 0, 64, FL_NORMAL_LABEL, 0, 14, 0},
 {"Recipes", 0,  (Fl_Callback*)Main_Window_CB, Address (Read_recipes_ingredients), 0, FL_NORMAL_LABEL, 0, 14, 0},
 {"Orders", 0,  (Fl_Callback*)Main_Window_CB, Address (Read_orders), 0, FL_NORMAL_LABEL, 0, 14, 0},
 {"Menu Items", 0,  (Fl_Callback*)Main_Window_CB, Address (Read_category_menu_items), 0, FL_NORMAL_LABEL, 0, 14, 0},
 {0,0,0,0,0,0,0,0,0},
 {"Show", 0,  0, 0, 64, FL_NORMAL_LABEL, 0, 14, 0},
 {"Orders", 0,  (Fl_Callback*)Main_Window_CB, Address (Show_order), 0, FL_NORMAL_LABEL, 0, 14, 0},
 {"Recipes", 0,  (Fl_Callback*)Main_Window_CB, Address (Show_recipe), 0, FL_NORMAL_LABEL, 0, 14, 0},
 {"Menu Items", 0,  (Fl_Callback*)Main_Window_CB, Address (Show_menu), 0, FL_NORMAL_LABEL, 0, 14, 0},
 {"Categories", 0,  (Fl_Callback*)Main_Window_CB, Address (Show_categories), 0, FL_NORMAL_LABEL, 0, 14, 0},
 {"Order Items", 0,  (Fl_Callback*)Main_Window_CB, Address (Show_order_items), 0, FL_NORMAL_LABEL, 0, 14, 0},
 {0,0,0,0,0,0,0,0,0},
 {"Find", 0,  0, 0, 64, FL_NORMAL_LABEL, 0, 14, 0},
 {"Category Sales", 0,  (Fl_Callback*)Main_Window_CB, Address (Find_server_sales), 0, FL_NORMAL_LABEL, 0, 14, 0},
 {"Table Sales", 0,  (Fl_Callback*)Main_Window_CB, Address (Find_table_sales), 0, FL_NORMAL_LABEL, 0, 14, 0},
 {"Menu Item Sales", 0,  (Fl_Callback*)Main_Window_CB, Address (Find_menu_item_sales), 0, FL_NORMAL_LABEL, 0, 14, 0},
 {0,0,0,0,0,0,0,0,0},
 {"Update", 0,  0, 0, 64, FL_NORMAL_LABEL, 0, 14, 0},
 {"Add Order Item", 0,  (Fl_Callback*)Main_Window_CB, Address (Update_add_order_item), 0, FL_NORMAL_LABEL, 0, 14, 0},
 {"Add Menu Item", 0,  (Fl_Callback*)Main_Window_CB, Address (Update_add_menu_item), 0, FL_NORMAL_LABEL, 0, 14, 0},
 {"Add Recipe", 0,  (Fl_Callback*)Main_Window_CB, Address (Update_add_recipe), 0, FL_NORMAL_LABEL, 0, 14, 0},
 {"Add Category", 0, (Fl_Callback*)Main_Window_CB, Address(Update_add_category), 0, FL_NORMAL_LABEL, 0, 14, 0}, //EC Part C
 {0,0,0,0,0,0,0,0,0},
 {"Graph", 0,  0, 0, 64, FL_NORMAL_LABEL, 0, 14, 0}, // NI -- part D
 {"Total Sales by Month", 0,  (Fl_Callback*)Main_Window_CB, Address (Graph_total_sales), 0, FL_NORMAL_LABEL, 0, 14, 0}, // NI -- part D
 {"Table Sales by ID", 0, (Fl_Callback*)Main_Window_CB, Address(Graph_table_sales), 0, FL_NORMAL_LABEL, 0, 14, 0},	//CZ Part D.2
 {"Server Sales by Month", 0,  (Fl_Callback*)Main_Window_CB, Address (Graph_server_sales), 0, FL_NORMAL_LABEL, 0, 14, 0}, //EC Part D3
 {0,0,0,0,0,0,0,0,0},
 {"About", 0,  0, 0, 64, FL_NORMAL_LABEL, 0, 14, 0},
 {"Info", 0,  (Fl_Callback*)Main_Window_CB, Address (About_info), 0, FL_NORMAL_LABEL, 0, 14, 0},
 {"Help", 0,  (Fl_Callback*)Main_Window_CB, Address (About_help), 0, FL_NORMAL_LABEL, 0, 14, 0},
 {0,0,0,0,0,0,0,0,0},
 {"Exit", 0,  0, 0, 64, FL_NORMAL_LABEL, 0, 14, 0},
 {"Save and exit", 0,  (Fl_Callback*)Main_Window_CB, Address (Exit_program), 0, FL_NORMAL_LABEL, 0, 14, 0},
 {0,0,0,0,0,0,0,0,0},
 {0,0,0,0,0,0,0,0,0}
};


//call back functions
void recps_cb(Address addr, Address) // callback for recipes button
{
	Main_Window_CB((Fl_Widget*) addr, Address (Tables_button));
}
void order_cb(Address addr, Address) // callback for orders button
{
	Main_Window_CB((Fl_Widget*) addr, Address (Orders_button));
}
void cat_cb(Address addr, Address) // callback for category button
{
	Main_Window_CB((Fl_Widget*) addr, Address (Categories_button));
}
void mi_cb(Address addr, Address) // callback for menu item button
{
	Main_Window_CB((Fl_Widget*) addr, Address (Menu_items_button));
}
void oi_cb(Address addr, Address) // callback for order item button
{
	Main_Window_CB((Fl_Widget*) addr, Address (Recipes_button));
}
 void display_cb(Address addr, Address) // callback for display window
{
	Main_Window_CB((Fl_Widget*) addr, Address (Display_window));
}
 void menu_bar_cb(Address addr, Address)//callback for menu bar
 {
	 Menu_Bar_CB((Fl_Widget*) addr, Address (Menu_bar_cb));
 }
 void find_total_sales_cb(Address addr, Address) // callback for find table sales button -- added by NI
{
	Main_Window_CB((Fl_Widget*) addr, Address (Find_table_sales_button));
}
 void add_new_order_cb(Address addr, Address) // callback for add new order button -- added by NI
{
	Main_Window_CB((Fl_Widget*) addr, Address (Add_order_item_button));
}
void find_item_sales_cb(Address addr, Address) //EC Part C: Callback for find menu item sales button.
{
	Main_Window_CB((Fl_Widget*) addr, Address (Find_item_sales_button));
}
void add_new_category_cb(Address addr, Address) //EC Part C: Callback for add new category button.
{
	Main_Window_CB((Fl_Widget*) addr, Address (Add_category_button));
}
/****Start by CZ for Step C****/
void find_server_sales_cb(Address addr, Address)
{
	Main_Window_CB((Fl_Widget*) addr, Address (Find_server_sales_button));
}
void add_menu_item_cb(Address addr, Address)
{
	Main_Window_CB((Fl_Widget*) addr, Address (Add_menu_item_button));
}
/****End by CZ for Step C****/
/******************/
/*Added by EC for Step B.2*/
/******************/
void show_recps_cb(Address addr, Address) // callback for "recipes" menu button
{
	Menu_Bar_CB((Fl_Widget*) addr, Address (Show_recipe));
}

void show_order_cb(Address addr, Address) // callback for "orders" menu button
{
	Menu_Bar_CB((Fl_Widget*) addr, Address (Show_order));
}

void show_menu_cb(Address addr, Address) // callback for "menu items" menu button
{
	Menu_Bar_CB((Fl_Widget*) addr, Address (Show_menu));
}
/********End part B.2 changes*********/

void Menu_Bar_CB (Fl_Widget*, void* ud) {
	cout << "Menu Bar Callback" << " Userdata=" << (int) ud << "\n";
	menu_bar_click = true;
}

void Main_Window_CB(Fl_Widget*, void* ud) {
	if(main_click_enabled)//don't signal the window click if main loop is active
	{
		cout << "Main Window Callback" << " Userdata=" << (int) ud << "\n";
		window_userdata = (int) ud;
		main_window_click = true;
		main_click_enabled = false; //main loop active on current click
	}
}
//wait functions for callbacks to be executed
void wait_for_main_window_click() {
	while (!main_window_click) 
		Fl::wait();
	main_window_click = false;
	Fl::redraw();
}

void wait_for_menu_bar_click() {
	while (!menu_bar_click)
		Fl::wait();
	menu_bar_click = false;
	Fl::redraw();
}

int main()
{
	//create the main window and display it
	ROMS_Menu m;
    Window sw(600, 500, "Restaurant Order Management System");
    Button recps(Point(40, 50), 100, 30, "Recipes", recps_cb);
	sw.attach(recps);
	Button order(Point(40, 100), 100, 30, "Orders", order_cb);
	sw.attach(order);
	Button cat(Point(40, 150), 100, 30, "Categories", cat_cb);
	sw.attach(cat);
	Button mi(Point(40, 200), 100, 30, "Menu Items", mi_cb);
	sw.attach(mi);
	Button ci(Point(40, 250), 100, 30, "Order Items", oi_cb);
	sw.attach(ci);
    sw.callback((Fl_Callback*)Main_Window_CB, Address (Exit_program));
	Menu_bar mb(Point(0, 0), 600, 30, menu_bar_cb);
    mb.menu(menu_bar);
	sw.attach(mb);

	Window_text_display t(Point(150,50),400, 400, "Data Display", display_cb );
	t.set_buffer("No Data Loaded\n");
	sw.attach(t);
 	sw.resizable(&sw);
	

	//main loop to execute user clicks on the main window
	//do you understand how this loop works compared to the way the main loop worked in Part I of the project?
	try {
		
		while(true) {
			main_click_enabled = true;
			wait_for_main_window_click();
			cout << "Act on userdata = " << window_userdata << endl;
			switch(window_userdata) 
			{
				//need to complete all the menu cases
				case Read_recipes_ingredients:
					do_read(sw, m, "recipes.dat", "Open Recipes/Ingredients File", Read_recipes_ingredients);
					recipes_read = true;
					break;
				case Read_orders:
					do_read(sw, m, "orders.dat", "Open Order/Order Items File", Read_orders);
					orders_read = true;
					break;
				case Read_category_menu_items:
					do_read(sw, m, "catmenu.dat", "Open Category/Menu Item File", Read_category_menu_items);
					catmenu_read = true;
					break;
				case About_info:
					do_about_box(sw);
					break;
				case About_help:
					do_help_box(sw);
					break;
				case Tables_button: case Orders_button: case Categories_button: case Recipes_button: case Menu_items_button: case Show_categories: case Show_order_items:
					t.set_buffer(m.show_button((Msg_type) window_userdata).c_str());
					break;
				/********************/
				/*Edited by EC for Step B.2*/
				/********************/
				case Show_order: case Show_recipe: case Show_menu:
					t.set_buffer(m.show_button((Msg_type) window_userdata).c_str());
					break; 
				//End part B.2
				case Find_table_sales: //added by NI -- find total sales
					find_total_sales_given_table_box(sw,m);
					break;
				case Update_add_order_item: //added by NI -- add new order item
					update_new_order_item_box(sw,m);
					break;
				case Find_menu_item_sales: //EC for Part C (find sales for a menu item)
					find_menu_item_sales_given_item_box(sw,m);
					break;
				case Update_add_category: //EC for Part C: add categories Soups, Salads, and Sides
					update_new_category_box(sw,m);
					break;
				/************************/
				/*Added by CZ for Step C*/
				case Find_server_sales:	
					find_server_sales_box(sw,m);
					break;
				case Update_add_menu_item:
					update_menu_item_box(sw,m);
					break;
				/************************/
				case Graph_total_sales: // NI -- part D
					draw_graph(sw,m);
					break;
				case Graph_table_sales:	// CZ Part D.2
					draw_table_graph(sw,m);
					break;
        case Graph_server_sales: //EC Part D3
					draw_server_graph(sw,m);
					break;
				case Exit_program:
					cout << "save files if opened and exit\n";
					if(orders_read) {m.write_orders();} //CZ B.1
					if(recipes_read) {m.write_recipes();} //CZ B.1
					if(catmenu_read) {m.write_catmenu();} //CZ B.1
					exit(0); //exit program
					break;
				default:
					cout << "case not implemented\n";
			}
		}
		return 0;
	}
	catch(exception& e) {
		cerr << "exception: " << e.what() << '\n';
		return 1;
	}
	catch (...) {
		cerr << "Some exception\n";
		return 2;
	}
}
//show about box info window
void do_about_box(Window& w) 
{
	Window ab(Point(w.x()+100, w.y()+100), 400, 120, "About Box");
	Image about_info(Point(0,0),"About_Info.gif"); //CZ B.1
	ab.color(Color::white);
	ab.callback((Fl_Callback*)Menu_Bar_CB, Address (Close_about_box));
	//Text msg(Point(15,50), "Ward Project Part II: Restaurant Order Management System");
	//msg.set_color(Color::black);
	//ab.attach(msg);
	ab.attach(about_info); //CZ B.1
	ab.set_label("About ROMS"); //CZ B.1
	wait_for_menu_bar_click();
	//ab.detach(msg);//clean up window
	ab.detach(about_info); //CZ B.1
	return;
}

//show about box help window -- added by NI B.3
void do_help_box(Window& w)
{
	Window win_help(Point(w.x()+100, w.y()+100), 700, 160, "Help");
	win_help.color(Color::white);
	win_help.callback((Fl_Callback*)Menu_Bar_CB, Address (Close_help_box));

	//add Text
	Text msg(Point(15,50), "Read the data first by simply clicking the Read Menu and choose the corresponding .dat files.");
	Text msg1(Point(15,70), "Show the data by clicking Button or Show Menu and choose the following data that you want to see.");
	Text msg2(Point(15,90), "Find the data by clicking Find Menu and choose the following data that you want to find.");
	Text msg3(Point(15,110), "Update the data by clicking the Update Menu and choose the following data that you want to update/add.");
	
	//set Text Color
	msg.set_color(Color::black);
	msg1.set_color(Color::black);
	msg2.set_color(Color::black);
	msg3.set_color(Color::black);
	
	//attach text to window
	win_help.attach(msg);
	win_help.attach(msg1);
	win_help.attach(msg2);
	win_help.attach(msg3);
	wait_for_menu_bar_click();
	
	//clean up window
	win_help.detach(msg);
	win_help.detach(msg1);
	win_help.detach(msg2);
	win_help.detach(msg3);
	return;
}

/****Start CZ Step C Code****/
void find_server_sales_box(Window& w, ROMS_Menu& m)
{
	Window win(Point(w.x()+100, w.y()+100), 320, 180, "Total Sales for Given Server");
	win.color(Color::white);
	win.callback((Fl_Callback*)Main_Window_CB, Address (Close_find_server_sales));
	
	Text command(Point(15,30), "Input Server ID in A Given Box Below");
	command.set_color(Color::black);
	win.attach(command);
	
	In_box in(Point(70,50), 50, 20, "ServerID:"); 
	win.attach(in);

	Text total(Point(15,90), "Server Sales: $");
	total.set_color(Color::black);
	win.attach(total);

	Button btnFind(Point(15, 120), 70, 30, "Find", find_server_sales_cb);
	win.attach(btnFind);	
	
    try {
        while(true) {
			main_click_enabled = true;
			wait_for_main_window_click();
			cout << "Act on userdata = " << window_userdata << endl;
			switch(window_userdata) 
			{
				case Find_server_sales_button:
					total.set_label(do_find_server_sales_button(in.get_int(), m));
					break;
				case Close_find_server_sales:
					cout << "exit";
					return;
					break;
				default:
					cout << "case not implemented\n";
			}
        }
    }
    catch(exception& e) {
        cerr << "exception: " << e.what() << '\n';
        return;
    }
    catch (...) {
        cerr << "Some exception\n";
        return;
    }

	//clean up window
    win.detach(command);
    win.detach(in);
    win.detach(btnFind);
	return;	
}

string do_find_server_sales_button(int table_id, ROMS_Menu& M)
{
        stringstream sstr;
        double total = M.find_server_sales(table_id);
        if (total == 0)
		{
			return "Server Sales: $0 (No sales found for given server)";
		}
		sstr << "Server Sales: $" << total;
        return sstr.str();
}

void update_menu_item_box(Window& w, ROMS_Menu& m)
{
	Window win(Point(w.x()+100, w.y()+100), 500, 300, "Add Menu Item");
    win.color(Color::white);
    win.callback((Fl_Callback*)Main_Window_CB, Address (Close_add_menu_item));

    Text command(Point(15,0), "Add Menu Item using an existing recipe to an existing category");
    command.set_color(Color::black);
    win.attach(command);
	
	In_box name(Point(60,20), 50,20, "Menu Item Name: ");
	win.attach(name);

    In_box men(Point(100, 50), 50, 20, "Menu Item ID: ");
    win.attach(men);
	
	Text menu_id_note(Point(154,64),"(2000-2999)");
	menu_id_note.set_color(Color::black);
	win.attach(menu_id_note);

    In_box category(Point(93, 80), 50, 20, "Category ID: ");
    win.attach(category);
	
	Text cat_id_note(Point(150,93),"(Existing)");
	cat_id_note.set_color(Color::black);
	win.attach(cat_id_note);

    In_box rec(Point(110, 110), 50, 20, "Recipe ID: ");
    win.attach(rec);

	Text rec_id_note(Point(167,113),"(Existing)");
	rec_id_note.set_color(Color::black);
	win.attach(rec_id_note);	
	
    In_box amt(Point(80, 140), 50, 20, "Amount: ");
    win.attach(amt);

	In_box desc(Point(90, 170), 80, 20, "Description: ");
	win.attach(desc);
	
	Text desc_note(Point(180, 182),"(Followed  by a #");
	desc_note.set_color(Color::black);
	win.attach(desc_note);
	
	//add Text result
    Text result(Point(15, 200), "");
    result.set_color(Color::black);
    win.attach(result);

	//add Add Button
	Button btnAdd(Point(15, 220), 70, 30, "Add", add_menu_item_cb);
    win.attach(btnAdd);	

    try {
        while(true) {
            main_click_enabled = true;
            wait_for_main_window_click();
            cout << "Act on userdata = " << window_userdata << endl;
            switch(window_userdata) 
            {
                case Add_menu_item_button:
                    result.set_label(m.add_menu_item(men.get_int(), category.get_int(), rec.get_int(), name.get_string(), amt.get_int(), desc.get_string()));
                    break;
                case Close_add_menu_item:
                    cout << "exit";
                    return;
                    break;
                default:
                    cout << "case not implemented\n";
            }
        }
    }
    catch(exception& e) {
        cerr << "exception: " << e.what() << '\n';
        return;
    }
    catch (...) {
        cerr << "Some exception\n";
        return;
    }

	//clean up window
    win.detach(command);
    win.detach(men);
    win.detach(btnAdd);
    return;	
}
/****End CZ Step C Code****/

///EC for Part C: find menu item sales for given menu item
void find_menu_item_sales_given_item_box(Window& w, ROMS_Menu& M)
{
	Window win(Point(w.x()+100, w.y()+100), 320, 180, "Total Sales for Given Menu Item");
	win.color(Color::white);
	win.callback((Fl_Callback*)Main_Window_CB, Address (Close_find_menu_item_sales));

	//add Text Command
	Text command(Point(15,30), "Input Menu Item ID in A Given Box Below");
	command.set_color(Color::black);
	win.attach(command);
	
	//add TextField
	In_box in(Point(105,50), 70, 20, "Menu Item ID:"); 
	win.attach(in);
	
	//add Text Total Sales
	Text total(Point(15,90), "Total Sales: $");
	total.set_color(Color::black);
	win.attach(total);
	
	//add Find Button
	Button btnFind(Point(15, 120), 70, 30, "Find", find_item_sales_cb);
	win.attach(btnFind);
	try {
		while(true) {
			main_click_enabled = true;
			wait_for_main_window_click();
			cout << "Act on userdata = " << window_userdata << endl;
			switch(window_userdata) 
			{
				case Find_item_sales_button:
					total.set_label(do_find_item_button(in.get_int(), M));
					break;
				case Close_find_menu_item_sales:
					cout << "exit";
					return;
					break;
				default:
					cout << "case not implemented\n";
			}
		}
	}
	catch(exception& e) {
        cerr << "exception: " << e.what() << '\n';
        return;
    }
    catch (...) {
        cerr << "Some exception\n";
        return;
    }

	//clean up window
    win.detach(command);
    win.detach(in);
    win.detach(btnFind);
	return;
}

//EC Part C: Output for item sales
string do_find_item_button(int item_id, ROMS_Menu& M)
{
        stringstream sstr;
        double total = M.total_menu_item_sales(item_id);
        if (total == 0)
		{
			return "Total Sales: $0 (No sales found for given menu item)";
		}
		sstr << "Total Sales: $" << total;
        return sstr.str();
}

//EC Part C: Update categories
void update_new_category_box(Window& w,ROMS_Menu& M)
{
	Window win(Point(w.x()+100, w.y()+100), 300, 250, "Add Category");
    win.color(Color::white);
    win.callback((Fl_Callback*)Main_Window_CB, Address (Close_add_category));

	//add Text Command
    Text command(Point(15,30), "Add Category");
    command.set_color(Color::black);
    win.attach(command);

	//add Text Field Category ID
    In_box cat(Point(100, 50), 50, 20, "Category ID: ");
    win.attach(cat);
	//add Text Category ID Note
	Text cat_id_note(Point(152,64),"(1000-1999)");
	cat_id_note.set_color(Color::black);
	win.attach(cat_id_note);

	//add Text Field Category Name
    In_box name(Point(122, 80), 50, 20, "Category Name: ");
    win.attach(name);
	
	//add Text result
    Text result(Point(15, 180), "");
    result.set_color(Color::black);
    win.attach(result);
	
	//add Add Button
	Button AddCat(Point(15, 200), 70, 30, "Add", add_new_category_cb);
    win.attach(AddCat);

    try {
        while(true) {
            main_click_enabled = true;
            wait_for_main_window_click();
            cout << "Act on userdata = " << window_userdata << endl;
            switch(window_userdata) 
            {
                case Add_category_button:
                    result.set_label(M.add_category(cat.get_int(), name.get_string()));
					//categories.push_back(Category(cat.get_int(), name.get_string()));
                    break;
                case Close_add_category:
                    cout << "exit";
                    return;
                    break;
                default:
                    cout << "case not implemented\n";
            }
        }
    }
    catch(exception& e) {
        cerr << "exception: " << e.what() << '\n';
        return;
    }
    catch (...) {
        cerr << "Some exception\n";
        return;
    }

	//clean up window
    win.detach(command);
	win.detach(cat);
	win.detach(cat_id_note);
	win.detach(name);
    win.detach(result);
    win.detach(AddCat);
    return;
}
//End EC Part C

//find total sales for given table box -- added by NI, find total sales for given table
void find_total_sales_given_table_box(Window& w,ROMS_Menu& M)
{
	Window win(Point(w.x()+100, w.y()+100), 320, 180, "Total Sales for Given Table");
	win.color(Color::white);
	win.callback((Fl_Callback*)Main_Window_CB, Address (Close_find_table_sales));
	
	//add Text Command
	Text command(Point(15,30), "Input TableID in A Given Box Below");
	command.set_color(Color::black);
	win.attach(command);
	
	//add TextField
	In_box in(Point(70,50), 50, 20, "TableID:"); 
	win.attach(in);

	//add Text Total Sales
	Text total(Point(15,90), "Total Sales: $");
	total.set_color(Color::black);
	win.attach(total);

	//add Find Button
	Button btnFind(Point(15, 120), 70, 30, "Find", find_total_sales_cb);
	win.attach(btnFind);

    try {
        while(true) {
			main_click_enabled = true;
			wait_for_main_window_click();
			cout << "Act on userdata = " << window_userdata << endl;
			switch(window_userdata) 
			{
				case Find_table_sales_button:
					total.set_label(do_find_table_button(in.get_int(), M));
					break;
				case Close_find_table_sales:
					cout << "exit";
					return;
					break;
				default:
					cout << "case not implemented\n";
			}
        }
    }
    catch(exception& e) {
        cerr << "exception: " << e.what() << '\n';
        return;
    }
    catch (...) {
        cerr << "Some exception\n";
        return;
    }

	//clean up window
    win.detach(command);
    win.detach(in);
    win.detach(btnFind);
	return;
}

//Total Sales output -- added by NI
string do_find_table_button(int table_id, ROMS_Menu& M)
{
        stringstream sstr;
        double total = M.total_sales_table(table_id);
        if (total == 0)
		{
			return "Total Sales: $0 (No sales found for given table)";
		}
		sstr << "Total Sales: $" << total;
        return sstr.str();
}

//update new order item box -- added by NI, add new order item
void update_new_order_item_box(Window& w,ROMS_Menu& M)
{
	Window win(Point(w.x()+100, w.y()+100), 300, 250, "Add Order Item");
    win.color(Color::white);
    win.callback((Fl_Callback*)Main_Window_CB, Address (Close_add_order_item));

	//add Text Command
    Text command(Point(15,30), "Add Order Item to Existing Order");
    command.set_color(Color::black);
    win.attach(command);

	//add Text Field OrderID
    In_box ord(Point(80, 50), 50, 20, "Order ID: ");
    win.attach(ord);
	//add Text OrderID Note
	Text order_id_note(Point(134,64),"(7000-7049)");
	order_id_note.set_color(Color::black);
	win.attach(order_id_note);

	//add Text Field SeatID
    In_box seat(Point(73, 80), 50, 20, "Seat ID: ");
    win.attach(seat);
	//add Text Seat Id Note
	Text seat_id_note(Point(130,93),"(A-Z)");
	seat_id_note.set_color(Color::black);
	win.attach(seat_id_note);

	//add Text Field MenuID
    In_box men(Point(110, 110), 50, 20, "Menu Item ID: ");
    win.attach(men);

	//add Text Field Quantity
    In_box qty(Point(80, 140), 50, 20, "Quantity: ");
    win.attach(qty);

	//add Text result
    Text result(Point(15, 180), "");
    result.set_color(Color::black);
    win.attach(result);

	//add Add Button
	Button btnAdd(Point(15, 200), 70, 30, "Add", add_new_order_cb);
    win.attach(btnAdd);

    try {
        while(true) {
            main_click_enabled = true;
            wait_for_main_window_click();
            cout << "Act on userdata = " << window_userdata << endl;
            switch(window_userdata) 
            {
                case Add_order_item_button:
                    result.set_label(M.add_order_item(ord.get_int(), men.get_int(), qty.get_int(), seat.get_string()));
                    break;
                case Close_add_order_item:
                    cout << "exit";
                    return;
                    break;
                default:
                    cout << "case not implemented\n";
            }
        }
    }
    catch(exception& e) {
        cerr << "exception: " << e.what() << '\n';
        return;
    }
    catch (...) {
        cerr << "Some exception\n";
        return;
    }

	//clean up window
    win.detach(command);
    win.detach(ord);
    win.detach(btnAdd);
    return;
}

//convert integer into Month -- added by NI, used in draw_graph function below
string toMonth(int i)
{
	string month;
	switch(i)
	{
	case 1:
		month = "January";
		break;
	case 2:
		month = "February";
		break;
	case 3:
		month = "March";
		break;
	case 4:
		month = "April";
		break;
	case 5:
		month = "May";
		break;
	case 6:
		month = "June";
		break;
	case 7:
		month = "July";
		break;
	case 8:
		month = "August";
		break;
	case 9:
		month = "September";
		break;
	case 10:
		month = "October";
		break;
	case 11:
		month = "November";
		break;
	case 12:
		month= "December";
		break;
	}
	return month;
}

//Step D.1 -- created by NI
void draw_graph(Window& w, ROMS_Menu& m)
{
	int scale = 50;
	int coordinate_x = 50;

	//create window
	Window win_graph(Point(w.x()+100, w.y()+100), 700, 450, "Graph for Total Sales By Month");
	win_graph.color(Color::white);
	win_graph.callback((Fl_Callback*)Menu_Bar_CB, Address (Close_graph));
	
	map<Point,double> sales;
	sales = m.order_sales_by_month();
	Point start = Point(0,0), end;
	map<Point,double>::iterator iter;
	for(iter=sales.begin(); iter!=sales.end(); ++iter)
	{
		if (start.x == 0 && start.y == 0)
		{
			start = (*iter).first;
		}
		cout << endl << (*iter).first.x << "," << (*iter).first.y << endl << (*iter).second;
		end = (*iter).first;
	}

	//axis line X's label
	ostringstream oss;
	oss << toMonth(start.x) << " " << start.y;

	//add axis line X with length = 600
	Axis x(Axis::x, Point(50,380), 600, (end.y - start.y)*12 + (end.x - start.x),"Sales from " + oss.str() + " (monthly)");
	x.set_color(Color::black);
	win_graph.attach(x);
	
	//add axis line Y with length = 350
	Axis y(Axis::y, Point(50,380), 350, (m.maximum_sales(sales) + scale)/scale,"Sales by $50 increments");
	y.set_color(Color::black);
	win_graph.attach(y);
	
	int current_month = start.x;
	int current_year = start.y;

	//draw polyline for the graph
	Open_polyline poly;
	poly.set_color(Color::black);
	for (int i = 0; i < (end.y-start.y)*12+(end.x-start.x)+1; i++)
	{
		poly.add(Point((coordinate_x + (current_month - start.x + (current_year - start.y) * 12) * (600/((end.y-start.y)*12+(end.x-start.x)))), 380 - (sales[Point(current_month,current_year)]/scale) * (350/((m.maximum_sales(sales)+scale)/scale)) )) ;
		current_month += 1;
		if (current_month > 12)
		{
			current_month = 1;
			current_year += 1;
		}
	}
	win_graph.attach(poly);

	wait_for_menu_bar_click();

	// clean up window
	win_graph.detach(x);
	win_graph.detach(y);
	return;
}

/****CREATED BY CZ PART D.2****/
void draw_table_graph(Window& w, ROMS_Menu& m)
{	
	//get graph data
	vector<Data_Table_Graph> data = m.create_table_graph_data();
	
	//create window
	Window win(Point(w.x()+100, w.y()+100), 700, 450, "Graph of Table Sales");
	win.color(Color::white);
	win.callback((Fl_Callback*)Menu_Bar_CB, Address (Close_table_graph));

	//create x axis
	Axis x(Axis::x, Point(50,380), 600, data.size(),"Table ID");
	x.set_color(Color::black);
	win.attach(x);
	
	//create y axis
	Axis y(Axis::y, Point(50,380), 350, 10,"Sales by $10 increments");
	y.set_color(Color::black);
	win.attach(y);
	
	//create bar lines for data
	vector<Line> lines;
	for(int i=0; i<data.size(); i++)
	{
		Point p1(50+i*(600/data.size()), 380);
		Point p2(50+i*(600/data.size()), data[i].get_table_sales()*3.5);
		Line l(p1,p2);
		l.set_color(Color::black);
		win.attach(l);
	}
	
	//draw bar lines with data
	for(int j=0; j<lines.size(); j++)
	{
		win.attach(lines[j]);
	}
	
	wait_for_menu_bar_click();

	// clean up window
	win.detach(x);
	win.detach(y);
	return;	
}
/****CREATED BY CZ PART D.2****/

//EC Part D3
void draw_server_graph(Window& w, ROMS_Menu& m)
{

	Window win_graph(Point(w.x()+100, w.y()+100), 700, 450, "Graph");
	win_graph.color(Color::white);
	win_graph.callback((Fl_Callback*)Menu_Bar_CB, Address (Close_server_graph));
	
	Text message(Point(15,30), "Graph should be here, but I wasn't able to get it to work.");
    message.set_color(Color::black);
    win_graph.attach(message);
	
	wait_for_menu_bar_click();
	
	//clean up window
	win_graph.detach(message);
	return;
}

void do_read(Window& w, ROMS_Menu& m, string dfn, string msg, Msg_type type)
{
	//Here again we linked our code directly to the FLTK library instead of creating an interface in our Graph_lib interface to FLTK
	//We did it for lack of time, which reflects the real word. Unfortunately if we wanted to move our code to a different graphics
	//library, we have to change our code and not just our Graphic_lib implementation. we are using the FLTK file chooser directly.
	Fl_File_Chooser fc(dfn.c_str(), "*.dat", Fl_File_Chooser::CREATE, msg.c_str());
	fc.show();
	while (fc.shown())
		Fl::wait();	//wait for OK or Cancel button
	if(0!=fc.value())//make sure there is a string to use as a filename
	{
		string fname = fc.value();
		switch(type) {
			case Read_recipes_ingredients:
				m.read_recipes_ingredients(fname);
				break;
			case Read_orders:
				m.Read_orders(fname);
				break;
			case Read_category_menu_items:
				m.read_catprds(fname);
				break;
			default:
				throw InvalidType();
		}
	}
	return;
}
